﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;

namespace iControl
{
    public sealed class Settings
    {
        #region Variable Declaration
        private const string ValueKey = "Value";
        private const string SettingsXmlRootKey = "Settings";
        private const string FadeInDurationKey = "FadeInDurtionMilliseconds";
        private const string FadeOutDurationKey = "FadeOutDurtionMilliseconds";
        private const string ShowPlaybackStatusKey = "ShowPlaybackStopped";
        private const string ShowDurationKey = "ShowDurationkey";
        private const string ShowNotifyIconKey = "ShowTrayIcon";
        private const double FadeInDurationDefaultVallue = 200;
        private const double FadeOutDurationDefaultValue = 500;
        private const bool ShowPlaybackStatusDefaultValue = false;
        private const int ShowDurationDefaultValue = 2;
        private const bool ShowNotifyIconDefaultValue = true;

        /// <summary>
        /// Used in lock-on block instead of class type to avoid deadlocks.
        /// </summary>
        private static object m_SyncRoot = new Object();
        #endregion

        #region Constructor
        /// <summary>
        /// Loads settings from the XML file. If file does not exist, assigns default values. Must be called before use.
        /// </summary>
        private Settings()
            : this(true) { }
        /// <summary>
        /// Loads settings from the XML file. If file does not exist, assigns default values. Must be called before use.
        /// </summary>
        private Settings(bool load)
        {
            if( !load )
                return;

            if( System.IO.File.Exists(SettingsFileLocation) )
            {
                var xTree = XElement.Load(SettingsFileLocation);
                double fadeValue;

                foreach( var element in xTree.Elements() )
                {
                    if( element.Name == FadeInDurationKey )
                    {
                        this.FadeInDuration = (double.TryParse(element.Value, out fadeValue)) ? fadeValue : FadeInDurationDefaultVallue;
                    }
                    else if( element.Name == FadeOutDurationKey )
                    {
                        this.FadeOutDuration = (double.TryParse(element.Value, out fadeValue)) ? fadeValue : FadeOutDurationDefaultValue;
                    }
                    else if( element.Name == ShowPlaybackStatusKey )
                    {
                        bool showValue;
                        this.ShowPlaybackStatus = (bool.TryParse(element.Value, out showValue)) ? showValue : ShowPlaybackStatusDefaultValue;
                    }
                    else if( element.Name == ShowDurationKey )
                    {
                        int showDuration;
                        this.ShowDuration = (int.TryParse(element.Value, out showDuration)) ? showDuration : ShowDurationDefaultValue;
                    }
                    else if( element.Name == ShowNotifyIconKey )
                    {
                        bool showNotifyIcon;
                        this.ShowNotifyIcon = (bool.TryParse(element.Value, out showNotifyIcon)) ? showNotifyIcon : ShowPlaybackStatusDefaultValue;
                    }
                }
            }
            else
            {
                SaveDefaultSettings();
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Save settings with default values to XML file.
        /// </summary>
        public bool SaveDefaultSettings()
        {
            Settings settings = new Settings(false)
            {
                FadeInDuration = FadeInDurationDefaultVallue,
                FadeOutDuration = FadeOutDurationDefaultValue,
                ShowPlaybackStatus = ShowPlaybackStatusDefaultValue,
                ShowDuration = 3,
                ShowNotifyIcon = ShowNotifyIconDefaultValue
            };

            this.FadeInDuration = settings.FadeInDuration;
            this.FadeOutDuration = settings.FadeOutDuration;
            this.ShowPlaybackStatus = settings.ShowPlaybackStatus;
            this.ShowDuration = settings.ShowDuration;
            this.ShowNotifyIcon = settings.ShowNotifyIcon;

            return settings.Save();
        }
        /// <summary>
        /// Updates dynamic properties of settings XML file to new values.
        /// </summary>
        public bool Save()
        {
            try
            {
                var xTree = new XElement(SettingsXmlRootKey);
                xTree.Add(new XElement(FadeInDurationKey, this.FadeInDuration));
                xTree.Add(new XElement(FadeOutDurationKey, this.FadeOutDuration));
                xTree.Add(new XElement(ShowPlaybackStatusKey, this.ShowPlaybackStatus));
                xTree.Add(new XElement(ShowDurationKey, this.ShowDuration));
                xTree.Add(new XElement(ShowNotifyIconKey, this.ShowNotifyIcon));

                xTree.Save(SettingsFileLocation);

                return true;
            }
            catch( Exception ex )
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);

                return false;
            }
        }
        #endregion

        #region Static Properties
        private static volatile Settings m_DefaultInstance;
        /// <summary>
        /// Gets default instance of Settings class.
        /// </summary>
        public static Settings DefaultInstance
        {
            get
            {
                if( m_DefaultInstance == null )
                {
                    //This double-check locking approach solves the thread concurrency problems while avoiding an exclusive 
                    //lock in every call to the Instance property method.
                    lock( m_SyncRoot )
                    {
                        if( m_DefaultInstance == null )
                            m_DefaultInstance = new Settings();
                    }
                }

                return m_DefaultInstance;
            }
        }
        #endregion

        #region Proeprties
        /// <summary>
        /// Gets or sets a value indicating whether showing track information when playback stopped.
        /// </summary>
        public bool ShowPlaybackStatus { get; set; }

        /// <summary>
        /// Gets or sets duration of track info window fade-in animation in milliseconds.
        /// </summary>
        public double FadeInDuration { get; set; }

        /// <summary>
        /// Gets or sets duration of track info window fade-out animation in milliseconds.
        /// </summary>
        public double FadeOutDuration { get; set; }

        /// <summary>
        /// Gets a value indincating how many seconds track info window should be shown till it fades out.
        /// </summary>
        public int ShowDuration { get; private set; }

        /// <summary>
        /// Gets or sets a value indicating whether application should show the notify icon.
        /// </summary>
        public bool ShowNotifyIcon { get; set; }

        /// <summary>
        /// Gets settings XML file location.
        /// </summary>
        private string SettingsFileLocation
        {
            get { return Application.StartupPath + "\\iControl.settings"; }
        }
        #endregion
    }
}
